package org.db.dao.query;

import java.util.List;

import org.db.dao.BauwerkslinienDAO;
import org.db.dao.HoehenlinienDAO;
import org.db.dao.KruemmungslinienDAO;
import org.db.dao.LageskizzenGVPDAO;
import org.db.dao.LageskizzenWeichenDAO;
import org.db.dao.UeberhoehungslinienDAO;

/**
 * @author Lutz Klasse zum Schreiben der Ergebnisse aus der km- Abfrage in die
 *         txt
 * 
 */
public class QueryResult {

	private double s0;

	private double hoeheBer;

	private String hoeheElement;

	private int uBer;

	private String uElement;

	private double g;

	private String mastpaar1Links;

	private String mastpaar2Links;

	private String mastpaar1Rechts;

	private String mastpaar2Rechts;

	private BauwerkslinienDAO nearestBauwerkslinienElement;

	private HoehenlinienDAO nearestHoehenlinienElement;

	private KruemmungslinienDAO nearestKruemmungslinienElement;

	private UeberhoehungslinienDAO nearestUeberhoehungslinienElement;

	private UeberhoehungslinienDAO nextUeberhoehungslinienElement;

	private UeberhoehungslinienDAO prevUeberhoehungslinienElement;

	private LageskizzenWeichenDAO nearestWeiche;

	private List<LageskizzenGVPDAO> nearestGVPs;

	public QueryResult(double s0,
			BauwerkslinienDAO nearestBauwerkslinienElement,
			HoehenlinienDAO nearestHoehenlinienElement,
			KruemmungslinienDAO nearestKruemmungslinienElement,
			UeberhoehungslinienDAO nearestUeberhoehungslinienElement,
			UeberhoehungslinienDAO nextUeberhoehungslinienElement,
			UeberhoehungslinienDAO prevUeberhoehungslinienElement,
			LageskizzenWeichenDAO nearestWeiche,
			List<LageskizzenGVPDAO> nearestGVPs) {
		this.s0 = s0;
		this.nearestBauwerkslinienElement = nearestBauwerkslinienElement;
		this.nearestHoehenlinienElement = nearestHoehenlinienElement;
		this.nearestKruemmungslinienElement = nearestKruemmungslinienElement;
		this.nearestUeberhoehungslinienElement = nearestUeberhoehungslinienElement;
		this.nextUeberhoehungslinienElement = nextUeberhoehungslinienElement;
		this.prevUeberhoehungslinienElement = prevUeberhoehungslinienElement;
		this.nearestWeiche = nearestWeiche;
		this.nearestGVPs = nearestGVPs;
	}

	public double gets0() {
		return s0;
	}

	public UeberhoehungslinienDAO getPrevUeberhoehungslinienElement() {
		return prevUeberhoehungslinienElement;
	}

	public void setPrevUeberhoehungslinienElement(
			UeberhoehungslinienDAO prevUeberhoehungslinienElement) {
		this.prevUeberhoehungslinienElement = prevUeberhoehungslinienElement;
	}

	public BauwerkslinienDAO getNearestBauwerkslinienElement() {
		return nearestBauwerkslinienElement;
	}

	public HoehenlinienDAO getNearestHoehenlinienElement() {
		return nearestHoehenlinienElement;
	}

	public KruemmungslinienDAO getNearestKruemmungslinienElement() {
		return nearestKruemmungslinienElement;
	}

	public UeberhoehungslinienDAO getNearestUeberhoehungslinienElement() {
		return nearestUeberhoehungslinienElement;
	}

	public UeberhoehungslinienDAO getNextUeberhoehungslinienElement() {
		return nextUeberhoehungslinienElement;
	}

	public LageskizzenWeichenDAO getNearestWeiche() {
		return nearestWeiche;
	}

	public List<LageskizzenGVPDAO> getNearestGVPs() {
		return nearestGVPs;
	}

	public void calculatGleisabstand() {
		List<LageskizzenGVPDAO> nearestGVPs = getNearestGVPs();
		LageskizzenGVPDAO gvp1;
		LageskizzenGVPDAO gvp2;
		if (nearestGVPs.size() == 2) {
			gvp1 = nearestGVPs.get(0);
			gvp2 = nearestGVPs.get(1);
			double g1 = gvp1.getgleisabstand();
			double g2 = gvp1.getgleisabstand();
			double dg = g2 - g1;
			double a = gvp2.getstationGVPLinks() - gvp1.getstationGVPLinks();
			double b = s0 - gvp1.getstationGVPLinks();
			g = (dg / a) * b + g1;
			mastpaar1Links = ("GVP-Links: " + gvp1.getpunktNrGVPLinks() + " / " + gvp1
					.getstationGVPLinks());
			mastpaar1Rechts = ("GVP-Rechts: " + gvp1.getpunktNrGVPRechts()
					+ " / " + gvp1.getstationGVPRechts());
			mastpaar2Links = ("GVP-Links: " + gvp2.getpunktNrGVPLinks() + " / " + gvp2
					.getstationGVPLinks());
			mastpaar2Rechts = ("GVP-Rechts: " + gvp2.getpunktNrGVPRechts()
					+ " / " + gvp2.getstationGVPRechts());
		} else if (nearestGVPs.size() == 1) {
			gvp1 = nearestGVPs.get(0);
			g = gvp1.getgleisabstand();
			mastpaar1Links = ("GVP-Links: " + gvp1.getpunktNrGVPLinks() + " / " + gvp1
					.getstationGVPLinks());
			mastpaar1Rechts = ("GVP-Rechts: " + gvp1.getpunktNrGVPRechts()
					+ " / " + gvp1.getstationGVPRechts());
		}
	}

	public void calculateUeberhoehung() {
		UeberhoehungslinienDAO ueberhoehungsElement = getNearestUeberhoehungslinienElement();
		if (ueberhoehungsElement != null) {
			UeberhoehungslinienDAO prevUeberhoehungsElement = getPrevUeberhoehungslinienElement();
			UeberhoehungslinienDAO nextUeberhoehungsElement = getNextUeberhoehungslinienElement();

			double sr = ueberhoehungsElement.getStationierungInMeterUe();
			int up = 0;
			if (prevUeberhoehungsElement != null) {
				if (prevUeberhoehungsElement.getUeberhoehungInMM() != 0) {
					up = prevUeberhoehungsElement.getUeberhoehungInMM();
				}
			}
			int un = 0;
			double l2 = 0;
			if (nextUeberhoehungsElement != null) {
				if (nextUeberhoehungsElement.getUeberhoehungInMM() != 0) {
					un = nextUeberhoehungsElement.getUeberhoehungInMM();
				}
				if (nextUeberhoehungsElement.getLaengeRampe() != 0) {
					l2 = nextUeberhoehungsElement.getLaengeRampe();
				}
			}
			double lr = ueberhoehungsElement.getLaengeRampe() != 0
					? ueberhoehungsElement.getLaengeRampe()
					: 0;
			if (lr != 0) {
				if (ueberhoehungsElement.getUeberhoehungsrampe().toString()
						.equals("RA")) {
					uElement = ("RA  Länge: " + lr);
					uBer = (int) (((s0 - sr) * un) / lr);
				} else if (ueberhoehungsElement.getUeberhoehungsrampe()
						.toString().equals("RAs")) {
					uElement = ("RAs  Länge: " + lr);
					uBer = (int) ((2 * (s0 - sr) * (s0 - sr) * un) / lr);
				} else if (ueberhoehungsElement.getUeberhoehungsrampe()
						.toString().equals("RAss")) {
					uElement = ("RAss  Länge: " + lr);
					uBer = (int) (up - (up / (lr * lr)) * (lr - s0) * (lr - s0));
				} else if (ueberhoehungsElement.getUeberhoehungsrampe()
						.toString().equals("REss")) {
					uElement = ("RAss  Länge: " + lr);
					uBer = (int) (up - (up / (lr * lr)) * (lr - s0) * (lr - s0));
				} else if (ueberhoehungsElement.getUeberhoehungsrampe()
						.toString().equals("RAB")) {
					uElement = ("RAB  Länge: " + lr);
					uBer = (int) (((3 * (s0 - sr) * (s0 - sr)) / (lr * lr) - (2
							* (s0 - sr) * (s0 - sr) * (s0 - sr))
							/ (lr * lr * lr)) * un);
				} else if (ueberhoehungsElement.getUeberhoehungsrampe()
						.toString().equals("RABs")) {
					uBer = (int) (up - (up / (lr * lr)) * (lr - s0) * (lr - s0));
					uElement = ("RABs  Länge: " + lr);
				} else if (ueberhoehungsElement.getUeberhoehungsrampe()
						.toString().equals("REBs")) {
					uBer = (int) (up - (up / (lr * lr)) * (lr - s0) * (lr - s0));
					uElement = ("REBs  Länge: " + lr);
				} else if (ueberhoehungsElement.getUeberhoehungsrampe()
						.toString().equals("RE")) {
					uElement = ("RE  Länge: " + lr);
					uBer = (int) (up - ((s0 - sr) * up) / lr);
				} else if (ueberhoehungsElement.getUeberhoehungsrampe()
						.toString().equals("REs")) {
					uElement = ("REs  Länge: " + lr);
					uBer = (int) (up - (2 * (s0 - sr) * (s0 - sr) * up) / lr);
				} else if (ueberhoehungsElement.getUeberhoehungsrampe()
						.toString().equals("REB")) {
					uElement = ("REB  Länge: " + lr);
					uBer = (int) (up - ((3 * (s0 - sr) * (s0 - sr)) / (lr * lr) - (2
							* (s0 - sr) * (s0 - sr) * (s0 - sr))
							/ (lr * lr * lr))
							* up);
				} else if (ueberhoehungsElement.getUeberhoehungsrampe()
						.toString().equals("RE")
						&& nextUeberhoehungsElement.getUeberhoehungsrampe()
								.toString().equals("RA")) {
					uElement = ("Gleisschere RE-RA");
					uBer = (int) ((up * (lr + l2)) * l2);
				} else if (ueberhoehungsElement.getUeberhoehungsrampe()
						.toString().equals("RA")
						&& nextUeberhoehungsElement.getUeberhoehungsrampe()
								.toString().equals("RE")) {
					uElement = ("Gleisschere RA-RE");
					uBer = (int) ((up * (lr + l2)) * l2);
				}
			} else if (ueberhoehungsElement.getUeberhoehungInMM() != 0) {
				uBer = (ueberhoehungsElement.getUeberhoehungInMM());
				uElement = " konstante Überhöhung";
			}
		} else {
			uBer = 0;
		}
	}

	public void calculateHoehe() {
		HoehenlinienDAO hoehenlinienElement = getNearestHoehenlinienElement();
		if (hoehenlinienElement != null) {
			double s = hoehenlinienElement.getStationierungInMeter();
			double h = hoehenlinienElement.gethoehe();
			double m1 = hoehenlinienElement.getNeigungAn();
			double m2 = hoehenlinienElement.getNeigungAb();
			int ra = hoehenlinienElement.getRa() != 0 ? hoehenlinienElement
					.getRa() : 0;
			double lt = hoehenlinienElement.getLt() != 0 ? hoehenlinienElement
					.getLt() : 0;
			double a = hoehenlinienElement.getA() != 0 ? hoehenlinienElement
					.getA() : 0;
			// NW mit Ausrundung
			if (ra != 0) {
				// s0 fällt nicht mit NW zusammen
				if (s0 != s) {
					// s0 kleiner StationNW, innerhalb der Ausrundung
					if ((s - lt) < s0 && s0 < s) {
						if (m2 < m1) {
							hoeheElement = "Ausrundungsbereich - Kuppe";
							hoeheBer = h - (m1 * lt) / 1000 - (s0 - (s - lt))
									* (m1 / 1000)
									- Math.pow((s0 - (s - lt)), 2) / (2 * ra);
						} else {
							hoeheElement = "Ausrundungsbereich - Wanne";
							hoeheBer = h - (m1 * lt) / 1000 + (s0 - (s - lt))
									* (m1 / 1000)
									+ Math.pow((s0 - (s - lt)), 2) / (2 * ra);
						}
						// s0 größer StationNW, innerhalb Ausrundung
					} else if (s < s0 && (s + lt) > s0) {
						if (m2 < m1) {
							hoeheElement = "Ausrundungsbereich - Kuppe";
							hoeheBer = h + (m2 * lt) / 1000 - ((s + lt) - s0)
									* (m2 / 1000)
									- Math.pow(((s + lt) - s0), 2) / (2 * ra);
						} else {
							hoeheElement = "Ausrundungsbereich - Wanne";
							hoeheBer = h + (m2 * lt) / 1000 + ((s + lt) - s0)
									* (m2 / 1000)
									+ Math.pow(((s + lt) - s0), 2) / (2 * ra);
						}
						// s0 kleiner StationNW, außerhalb der Ausrundung
					} else if (s0 < (s - lt)) {
						hoeheBer = h - (m1 * (s - s0)) / 1000;
						hoeheElement = "Neigungsbereich";
						// s0 größer StationNW, außerhalb Ausrundung
					} else if (s0 > (s + lt)) {
						hoeheBer = h + (m2 * (s0 - s)) / 1000;
						hoeheElement = "Neigungsbereich";
					}
				} else {
					if (m2 < m1) {
						hoeheElement = "Ausrundungsbereich - Kuppe";
						hoeheBer = h + a;
					} else {
						hoeheElement = "Ausrundungsbereich - Wanne";
						hoeheBer = h + a;
					}
				}
			} else {
				// s0 im Neigungsbereich
				if (s0 != s) {
					if (s0 < s) {
						hoeheBer = h - (m1 * (s - s0)) / 1000;
						hoeheElement = "Neigungsbereich";
					} else {
						hoeheBer = h + (m2 * (s0 - s)) / 1000;
						hoeheElement = "Neigungsbereich";
					}
				} else {
					hoeheBer = h;
					hoeheElement = "Neigungswechsel";
				}
			}
		}
	}

	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder();
		calculateHoehe();
		calculateUeberhoehung();
		calculatGleisabstand();
		sb.append("\n");
		// für Bauwerkslinie
		sb.append("Bauwerkslinie");
		sb.append("\n");
		sb.append("Bauwerk: ");
		if (nearestBauwerkslinienElement != null) {
			sb.append(nearestBauwerkslinienElement.getBauwerk());
		}
		sb.append("\n");
		sb.append("Station von: ");
		if (nearestBauwerkslinienElement != null) {
			sb.append(nearestBauwerkslinienElement.getStationierungVonInMeter())
					.append("m");
		}
		sb.append("\n");
		sb.append("Station bis: ");
		if (nearestBauwerkslinienElement != null) {
			sb.append(nearestBauwerkslinienElement.getStationierungBisInMeter())
					.append("m");
		}
		sb.append("\n");
		sb.append("Höhe Bauwerk: ");
		if (nearestBauwerkslinienElement != null) {
			sb.append(nearestBauwerkslinienElement.getHoeheInMeter()).append(
					"m");
		}
		sb.append("\n");
		sb.append("Besonderheiten: ");
		if (nearestBauwerkslinienElement != null) {
			sb.append(nearestBauwerkslinienElement.getBesonderheiten());
		}
		sb.append("\n");
		sb.append("\n");
		// Für Höhenlinie
		sb.append("Höhenlinie");
		sb.append("\n");
		sb.append("Höhe: ");
		if (nearestHoehenlinienElement != null) {
			sb.append(hoeheBer);
		}
		sb.append("\n");
		sb.append("Element: ");
		if (nearestHoehenlinienElement != null) {
			sb.append(hoeheElement);
		}
		sb.append("\n");
		sb.append("\n");
		// Für Überhöhungslinie
		sb.append("Überhöhungslinie");
		sb.append("\n");
		sb.append("Überhöhung: ");
		if (nearestUeberhoehungslinienElement != null) {
			sb.append(uBer);
		} else {
			sb.append("0");
		}
		sb.append("\n");
		sb.append("Element: ");
		if (nearestUeberhoehungslinienElement != null) {
			sb.append(uElement);
		}
		sb.append("\n");
		sb.append("Station von: ");
		if (nearestUeberhoehungslinienElement != null) {
			sb.append(
					nearestUeberhoehungslinienElement
							.getStationierungInMeterUe()).append("m");
		}
		sb.append("\n");
		sb.append("Station bis: ");
		if (nearestUeberhoehungslinienElement != null) {
			sb.append(
					nearestUeberhoehungslinienElement
							.getEndstationierungInMeterUE()).append("m");
		}
		sb.append("\n");
		sb.append("\n");
		// Für Krümmungslinie
		sb.append("Krümmungslinie");
		sb.append("Element: ");
		if (nearestKruemmungslinienElement != null) {
			sb.append(nearestKruemmungslinienElement.getElement());
		}
		sb.append("\n");
		sb.append("Station von: ");
		if (nearestKruemmungslinienElement != null) {
			sb.append(nearestKruemmungslinienElement.getStationierungInMeter())
					.append("m");
		}
		sb.append("\n");
		sb.append("Station bis: ");
		if (nearestKruemmungslinienElement != null) {
			sb.append(
					nearestKruemmungslinienElement.getEndstationierungInMeter())
					.append("m");
		}
		sb.append("\n");
		sb.append("\n");
		// Für Lageskizze
		sb.append("Lageskizze");
		sb.append("\n");
		sb.append("Gleisabstand: ");
		if (g != 0) {
			sb.append(g);
		}
		sb.append("\n");
		if (nearestGVPs != null) {
			sb.append("Mastpaar 1: ");
			sb.append("\n");
			sb.append(mastpaar1Links);
			sb.append("\n");
			sb.append(mastpaar1Rechts);
		}
		sb.append("\n");
		if (nearestGVPs.size() == 2) {
			sb.append("Mastpaar 2: ");
			sb.append("\n");
			sb.append(mastpaar2Links);
			sb.append("\n");
			sb.append(mastpaar2Rechts);
		}
		sb.append("");
		return sb.toString();
	}

}
